/**
 *
 */
package de.cbf.cam.dsa.facet.item;

import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.cbf.cam.dsa.facet.item.helper.Shapeness;
import de.cbf.util.entity.facet.constants.ConstantsFontColorLogView;
import de.cbf.util.entity.facet.entities.EntityCategorized;
import de.cbf.util.entity.facet.entities.FacetOfEntity;
import de.cbf.util.entity.facet.util.TextPartStyled;
import de.cbf.util.uuidheader.entities.UUIDHeader;
import de.cbf.util.uuidheader.exceptions.EntityMergeException;

/**
 * @author Nebelritter
 * LATER needs x,y,z max and x,y,z, min for dimensions or make dimensions class
 */
@XmlRootElement(name="item")
@XmlAccessorType(XmlAccessType.FIELD)
public class FacetItem extends FacetOfEntity implements FacetItemConstants{
	private static final Log logger = LogFactory.getLog(FacetItem.class);
	
	protected Double 	fWeight;
	protected String 	fDescription;
	protected String 	fType;	
	protected Long		fValueKreuzer;
	/**
	 * the quality of the item, just how well it was made,
	 * not the shape it is in(well made, but broken is possible)
	 */
	protected Double 	fQuality;
	/**
	 * the min quality that the item exists in
	 */
	protected Double 	fQualityMin;
	/**
	 * the max quality that the item exists in
	 */
	protected Double 	fQualityMax;
	/**
	 * item shape and possible shapes
	 */
	protected Shapeness fBrokenness;
	protected Shapeness fDirtiness;
	
	protected PCLBrokenness pclBrokenness;
	protected PCLDirtiness	pclDirtiness;	

	public FacetItem() {
		super();
	}

	public FacetItem(String name) {
		super(name);
	}

	protected void init(){
		super.init();
		pclBrokenness 	= new PCLBrokenness();
		pclDirtiness	= new PCLDirtiness();
		
		fName			= "";
		fDescription	= UNSET_DESCRIPTION;
		fWeight 		= UNSET_WEIGHT;		
		fType			= UNSET_TYPE;
		fQuality 		= UNSET_QUALITY;
		fQualityMin 	= UNSET_QUALITY_MIN;
		fQualityMax 	= UNSET_QUALITY_MAX;		
		fValueKreuzer   = UNSET_VALUE_KREUZER;
		
		fBrokenness = new Shapeness();
		fBrokenness.getPropertyChangeSupport().addPropertyChangeListener(pclBrokenness);
		setBrokennessDescriptions(new ArrayList<String>());
		
		fDirtiness = new Shapeness();
		fDirtiness.getPropertyChangeSupport().addPropertyChangeListener(pclDirtiness);	
		setDirtinessDescriptions(new ArrayList<String>());
	}
	
	@Override
	protected void doMergeDataFrom(UUIDHeader entity, boolean i_am_older)
			throws EntityMergeException {
		super.doMergeDataFrom(entity, i_am_older);
		if (entity instanceof FacetItem) {
			FacetItem other = (FacetItem) entity;
			if(i_am_older){
				this.fWeight = other.fWeight;
				this.fDescription = other.fDescription;
				this.fType = other.fType;
				this.fValueKreuzer = other.fValueKreuzer;
				this.fQuality = other.fQuality;
				this.fQualityMin = other.fQualityMin;
				this.fQualityMax = other.fQualityMax;
				try{
					this.fBrokenness = (Shapeness) other.fBrokenness.clone();
					this.fDirtiness = (Shapeness) other.fDirtiness.clone();
				}catch(CloneNotSupportedException exc){
					throw new EntityMergeException(exc);
				}				
			}
		}else{
			String mergeEntityClass = entity == null? "null":entity.getClass().getName();
			String errorMsg ="EntityToMerge "+mergeEntityClass+" does not fit class:"+this.getClass().getName();
			throw new EntityMergeException(errorMsg);
		}
	}

	@Override
	public List<TextPartStyled> getFacetStyledDescription() {
		
		List<TextPartStyled> textStyleInfo = new ArrayList<TextPartStyled>();
		
		TextPartStyled textPart;
		//item heading
		textPart = new TextPartStyled();
		textPart.setText(TEXT_LOG_HEADING_ITEM+"\n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_FACET);		
		textStyleInfo.add(textPart );
		
		//fWeight		
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_WEIGHT);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );
		//fWeight value
		textPart = new TextPartStyled();
		textPart.setText(fWeight+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fDescription
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_DESCRIPTION);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );		
		//fDescription value		
		textPart = new TextPartStyled();
		textPart.setText(fDescription+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		//fType
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_TYPE);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );		
		//fType value
		textPart = new TextPartStyled();
		textPart.setText(fType+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );

		//fValueKreuzer
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_VALUE_KREUZER);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );
		//fValueKreuzer value
		textPart = new TextPartStyled();
		textPart.setText(fValueKreuzer+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );		

		//fQuality
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_QUALITY);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );		
		//fQuality value	
		textPart = new TextPartStyled();
		textPart.setText(fQuality+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );		

		//fQualityMin
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_QUALITY_MIN);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );	
		//fQualityMin value	
		textPart = new TextPartStyled();
		textPart.setText(fQualityMin+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );		

		//fQualityMax
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_QUALITY_MAX);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );
		//fQualityMax value		
		textPart = new TextPartStyled();
		textPart.setText(fQualityMax+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );		

		//fBrokenness
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_BROKENNESS);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );		
		//fBrokenness value	
		textPart = new TextPartStyled();
		textPart.setText(fBrokenness.getShapenessDescriptions()+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart);		
					
		//fDirtiness
		textPart = new TextPartStyled();
		textPart.setText("\t"+TEXT_LOG_DIRTINESS);
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_CATEGORY);		
		textStyleInfo.add(textPart );		
		//fDirtiness value	
		textPart = new TextPartStyled();
		textPart.setText(fDirtiness.getShapenessDescriptions()+" \n");
		textPart.setStyleConstant(ConstantsFontColorLogView.STYLE_VALUE);		
		textStyleInfo.add(textPart );
		
		return textStyleInfo;
	}
	
	@Override
	public String hasUnsetValues() {
		StringBuffer result = new StringBuffer();
		if(UNSET_WEIGHT.equals(fWeight)){
			result.append(TEXT_UNSET_WEIGHT+"\n");
		}
		if(UNSET_DESCRIPTION.equals(fDescription)){
			result.append(TEXT_UNSET_DESCRIPTION+"\n");
		}
		if(UNSET_TYPE.equals(fType)){
			result.append(TEXT_UNSET_TYPE+"\n");
		}
		if(UNSET_VALUE_KREUZER.equals(fValueKreuzer)){
			result.append(TEXT_UNSET_VALUE_KREUZER+"\n");
		}
		if(UNSET_QUALITY.equals(fQuality)){
			result.append(TEXT_UNSET_QUALITY+"\n");
		}
		if(UNSET_QUALITY_MIN.equals(fQualityMin)){
			result.append(TEXT_UNSET_QUALITY_MIN+"\n");
		}
		if(UNSET_QUALITY_MAX.equals(fQualityMax)){
			result.append(TEXT_UNSET_QUALITY_MAX+"\n");
		}
		if(fBrokenness.getShapenessDescriptions().isEmpty()){
			result.append(TEXT_UNSET_BROKENNESS_DESCRIPTIONS+"\n");
		}
		if(fDirtiness.getShapenessDescriptions().isEmpty()){
			result.append(TEXT_UNSET_DIRTINESS_DESCRIPTIONS+"\n");
		}
		return result.toString();
	}

	/* (non-Javadoc)
	 * @see de.cbf.util.entity.facet.entities.FacetOfEntity#setDeleted(java.lang.Long)
	 */
	@Override
	public void setDeleted(Long aDeleted) {		
		super.setDeleted(aDeleted);
		fDirtiness.setDeleted(aDeleted);
		fBrokenness.setDeleted(aDeleted);		
	}
	
	@Override
	public PropertyChangeListener getEntityPropertyChangeListener() {		
		return getPCLTypeUpdate();
	}
	
	public String dirtyItem(Integer level, List<String> reasons){
		fDirtiness.incShapenessLevelBy(level, reasons);
		return fDirtiness.getCurrentShapenessDescription();
	}

	public String cleanItem(Integer level, List<String> reasons){
		fDirtiness.decShapenessLevelBy(level, reasons);
		return fDirtiness.getCurrentShapenessDescription();
	}

	public String breakItem(Integer level, List<String> reasons){
		fBrokenness.incShapenessLevelBy(level, reasons);
		return fBrokenness.getCurrentShapenessDescription();
	}

	public String fixItem(Integer level, List<String> reasons){
		fBrokenness.decShapenessLevelBy(level, reasons);
		return fBrokenness.getCurrentShapenessDescription();
	}

	public List<String> getDirtinessDescriptions() {
		return fDirtiness.getShapenessDescriptions();
	}

	public void setDirtinessDescriptions(List<String> shapenessDescriptions) {
		fDirtiness.setShapenessDescriptions(shapenessDescriptions);
		propertyChangeSupport.fireIndexedPropertyChange(PN_DIRTINESS_LEVELS, PI_DIRTINESS_LEVELS,
				null,this.fDirtiness);
	}

	public List<String> getBrokennessDescriptions() {
		return fBrokenness.getShapenessDescriptions();
	}

	public void setBrokennessDescriptions(List<String> shapenessDescriptions) {
		fBrokenness.setShapenessDescriptions(shapenessDescriptions);
		propertyChangeSupport.fireIndexedPropertyChange(PN_BROKENNESS_LEVELS, PI_BROKENNESS_LEVELS,
				null,this.fBrokenness);
	}

	public String getDescription() {
		return fDescription;
	}

	public void setDescription(String description) {
		String oldDescription = this.fDescription;
		this.fDescription = description;
		propertyChangeSupport.fireIndexedPropertyChange(PN_DESCRIPTION, PI_DESCRIPTION,
				oldDescription,this.fDescription);
	}

	public Double getWeight() {
		return fWeight;
	}

	public void setWeight(Double weight) {
		Double oldWeight = this.fWeight;
		this.fWeight = weight;
		propertyChangeSupport.fireIndexedPropertyChange(PN_WEIGHT, PI_WEIGHT,
				oldWeight,this.fWeight);
	}

	public String getType() {
		return fType;
	}

	public void setType(String type) {
		String oldType = this.fType;
		this.fType = type;
		propertyChangeSupport.fireIndexedPropertyChange(PN_TYPE, PI_TYPE,
				oldType,this.fType);
	}

	public Double getQuality() {
		return fQuality;
	}

	public void setQuality(Double quality) {
		Double oldQuality = this.fQuality;
		this.fQuality = quality;
		propertyChangeSupport.fireIndexedPropertyChange(PN_QUALITY_CURRENT, PI_QUALITY_CURRENT,
				oldQuality,this.fQuality);

	}

	public Double getQualityMin() {
		return fQualityMin;
	}

	public void setQualityMin(Double minQuality) {
		Double oldQuality = this.fQualityMin;
		this.fQualityMin = minQuality;
		propertyChangeSupport.fireIndexedPropertyChange(PN_QUALITY_MIN, PI_QUALITY_MIN,
				oldQuality,this.fQualityMin);
	}

	public Double getQualityMax() {
		return fQualityMax;
	}

	public void setQualityMax(Double maxQuality) {
		Double oldQuality = this.fQualityMax;
		fQualityMax = maxQuality;
		propertyChangeSupport.fireIndexedPropertyChange(PN_QUALITY_MAX, PI_QUALITY_MAX,
				oldQuality,fQualityMax);
	}

	public Shapeness getDirtiness() {
		return fDirtiness;
	}

	public void setDirtiness(Shapeness newDirtiness) {
		if(fDirtiness != null){
			fDirtiness.getPropertyChangeSupport().removePropertyChangeListener(pclDirtiness);
		}
		Shapeness oldDirtiness = fDirtiness;
		fDirtiness = newDirtiness;
		fDirtiness.getPropertyChangeSupport().addPropertyChangeListener(pclDirtiness);
		propertyChangeSupport.fireIndexedPropertyChange(PN_DIRTINESS, PI_DIRTINESS,
				oldDirtiness,fDirtiness);
	}

	public Shapeness getBrokenness() {
		return fBrokenness;
	}

	public void setBrokenness(Shapeness newBrokenness) {
		if(fBrokenness != null){
			fBrokenness.getPropertyChangeSupport().removePropertyChangeListener(pclBrokenness);
		}
		Shapeness oldBrokenness = fBrokenness;
		fBrokenness = newBrokenness;
		fBrokenness.getPropertyChangeSupport().addPropertyChangeListener(pclBrokenness);
		propertyChangeSupport.fireIndexedPropertyChange(PN_BROKENNESS, PI_BROKENNESS,
				oldBrokenness,fBrokenness);
	}

	public Long getValueKreuzer() {
		return fValueKreuzer;
	}

	public void setValueKreuzer(Long newValueKreuzer) {
		Long oldValueKreuzer = this.fValueKreuzer;
		this.fValueKreuzer = newValueKreuzer;
		propertyChangeSupport.fireIndexedPropertyChange(PN_VALUE_KREUZER, PI_VALUE_KREUZER,
				oldValueKreuzer,this.fValueKreuzer);
	}

	protected class PCLBrokenness implements PropertyChangeListener{
		@Override
		public void propertyChange(java.beans.PropertyChangeEvent evt) {
			propertyChangeSupport.fireIndexedPropertyChange(PN_BROKENNESS_PROPS,PI_BROKENNESS_PROPS,null,evt);			
		}	
	}

	protected class PCLDirtiness implements PropertyChangeListener{
		@Override
		public void propertyChange(java.beans.PropertyChangeEvent evt) {
			propertyChangeSupport.fireIndexedPropertyChange(PN_DIRTINESS_PROPS,PI_DIRTINESS_PROPS,null,evt);			
		}		
	}

	protected PCL_TypeUpdate pclTypeUpdate;
	protected PropertyChangeListener getPCLTypeUpdate() {
		if(pclTypeUpdate == null){
			pclTypeUpdate = new PCL_TypeUpdate();
		}
		return pclTypeUpdate;
	}
	protected class PCL_TypeUpdate implements PropertyChangeListener{
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt instanceof IndexedPropertyChangeEvent) {
				IndexedPropertyChangeEvent idxEvt = (IndexedPropertyChangeEvent) evt;
				int index = idxEvt.getIndex();
				switch (index) {
					case EntityCategorized.PI_PARENT_CATEGORY_NAME:{
						Object newValue = idxEvt.getNewValue();
						if (newValue instanceof String) {
							String newString = (String) newValue;
							//only replace if nothing else is written there, so it will not change by changing category, 
							//if type is already set
							if(UNSET_TYPE.equals(fType)){
								fType = newString;
							}							
						} else {
							String err_msg = "entity of wrong type in propertyChange : \n"
									+ "Expected: "
									+ String.class.getSimpleName()
									+ "\n"
									+ "Got: "
									+ (newValue == null ? "null" : newValue
											.getClass().getSimpleName());
							logger.error(err_msg);
						}						 
						break;
					}
					default:
						break;
				}
			} 
		}		
	}
}
